using Project3D.my3D.Base;
using Project3D.my3D.Geometric;
using Project3D.my3D.Structure;
using System;
using System.Collections.Generic;

namespace Project3D.my3D
{

    public class myUtil
    {
        //Computes the dot-product of the two vectors u and v.
        public static double computeDotproduct(myVector3D u, myVector3D v)
        {
            return u.dX * v.dX + u.dY * v.dY + u.dZ * v.dZ;
        }

        //Computes the vector-product of the two vectors u and v and put into variable "result".
        public static void computeVectorproduct(myVector3D u, myVector3D v, myVector3D result)
        {
            result.dX = u.dY * v.dZ - u.dZ * v.dY;
            result.dY = u.dZ * v.dX - u.dX * v.dZ;
            result.dZ = u.dX * v.dY - u.dY * v.dX;
        }

        //computes the normal vector of the plane spanned by v1, v2, v3 and put in variable "vec".
        public static void computeNormal(myVertex v1, myVertex v2, myVertex v3, myVector3D vec)
        {
            myUtil.computeVectorproduct(v2.point - v1.point, v3.point - v2.point, vec);
            vec.normalize();
        }

        //Computes the plane containing the triangle and put in variable "result".
        public static void computePlane(myTriangle3D t, myPlane3D result)
        {
            myUtil.computeNormal(new myVertex(t.p1), new myVertex(t.p2), new myVertex(t.p3), result.normal);
            result.p0 = t.p1;
        }

        public static void computePlaneOfFace(myFace f, myPlane3D result)
        {
            result.normal = new myVector3D();
            myUtil.computeNormal(f.adjacent_halfedge.source, f.adjacent_halfedge.next.source, f.adjacent_halfedge.next.next.source, result.normal);
            result.p0 = f.adjacent_halfedge.source.point;
        }

        //computes the intersection of the line variable "line" with the plane variable "plane". Returns the value of t so that the intersection point is line.p + t*line.v.
        public static double computeIntersection(myLine3D line, myPlane3D plane)
        {
            if (myUtil.computeDotproduct(line.v, plane.normal) == 0)
                return 0;
            else
                return myUtil.computeDotproduct(plane.p0 - line.p, plane.normal) / myUtil.computeDotproduct(line.v, plane.normal);
        }

        //Computes the closest point between a point and a plane in 3D and put in variable "result".
        public static void computeClosest(myPoint3D p, myPlane3D h, myPoint3D result)
        {
            myLine3D tmpLine = new myLine3D(p, h.normal);
            myPoint3D tmpResult = tmpLine.pointat(myUtil.computeIntersection(tmpLine, h));

            result.X = tmpResult.X;
            result.Y = tmpResult.Y;
            result.Z = tmpResult.Z;
        }

        public static void computeRotation(myPoint3D p, myLine3D l, double theta, myPoint3D output)
        {
            l.v.normalize();
            double a = l.p.X, b = l.p.Y, c = l.p.Z, x = p.X, y = p.Y, z = p.Z, u = l.v.dX, v = l.v.dY, w = l.v.dZ;
            double cosTheta = Math.Cos(theta), sinTheta = Math.Sin(theta);

            output.X = (a * (v * v + w * w) - u * (b * v + c * w - u * x - v * y - w * z)) * (1 - cosTheta) + x * cosTheta + (-c * v + b * w - w * y + v * z) * sinTheta;
            output.Y = (b * (u * u + w * w) - v * (a * u + c * w - u * x - v * y - w * z)) * (1 - cosTheta) + y * cosTheta + (c * u - a * w + w * x - u * z) * sinTheta;
            output.Z = (c * (u * u + v * v) - w * (a * u + b * v - u * x - v * y - w * z)) * (1 - cosTheta) + z * cosTheta + (-b * u + a * v - v * x + u * y) * sinTheta;
        }

    }

}
